package org.liquidByte.trafficMustang.androidApp.activities;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.liquidByte.trafficMustang.R;
import org.liquidByte.trafficMustang.androidApp.App;
import org.liquidByte.trafficMustang.androidApp.LocationTracker;
import org.liquidByte.trafficMustang.androidApp.dialogs.RatingDialog;
import org.liquidByte.trafficMustang.androidApp.listview.adapter.DisplayNoDataAdapter;
import org.liquidByte.trafficMustang.androidApp.listview.adapter.EventsAdapter;
import org.liquidByte.trafficMustang.androidApp.listview.row.AceiteRow;
import org.liquidByte.trafficMustang.androidApp.listview.row.AvaliacaoRow;
import org.liquidByte.trafficMustang.androidApp.listview.row.DeslocamentoRow;
import org.liquidByte.trafficMustang.androidApp.listview.row.RowActionListener;
import org.liquidByte.trafficMustang.androidApp.listview.row.TrechoRow;
import org.liquidByte.trafficMustang.androidApp.services.AvaliacaoService;
import org.liquidByte.trafficMustang.androidApp.services.DeslocamentoService;
import org.liquidByte.trafficMustang.androidApp.services.MainService;
import org.liquidByte.trafficMustang.androidApp.services.Services;
import org.liquidByte.trafficMustang.androidApp.services.TrechoService;
import org.liquidByte.trafficMustang.androidApp.services.dto.AvaliacaoDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.DeslocamentoDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.LocalizacaoDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.MainDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.MensagemDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.TrechoDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.UpdatesDTO;
import org.liquidByte.trafficMustang.androidApp.services.dto.UsuarioDTO;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends ModelActivity<MainDTO> implements OnClickListener {
	
	private static final int OPTIONS_MENU_ITEM_CONFIGURATION = 1;
	private static final int REQUEST_CODE_INFORMAR_DESLOCAMENTO = 1;
	private static final int REQUEST_CODE_REQUISITAR_TRECHO = 2;
	private static MainActivity instance;
	
	private ImageButton imgbInformarDeslocamento;
	private ImageButton imgbRequisitarCarona;
	private ImageButton imgbMudarPerfil;
	private ListView lstvEvents;
	private EventsAdapter eventsAdapter;
	private DisplayNoDataAdapter noDataEventsAdapter;
	private TextView txvPerfil;
	private ScheduledExecutorService updatePool;
	private boolean updating;
	
    public MainActivity() {
		super(R.layout.main, MainDTO.class, true);
		
		MainActivity.instance = this;
	}
    
    
    protected DisplayNoDataAdapter getNoDataEventsAdapter() {
    	if (this.noDataEventsAdapter == null) {
			this.noDataEventsAdapter = new DisplayNoDataAdapter(this, this.getEventsAdapter());
		}
		return noDataEventsAdapter;
	}
	private ScheduledExecutorService getUpdatePool() {
    	if (this.updatePool == null) {
			this.updatePool = Executors.newSingleThreadScheduledExecutor();
		}
    	return this.updatePool;
    }
    private void setUpdatePool(ScheduledExecutorService service) {
    	if (!(service == null && this.updatePool == null ||
    		  service != null && this.updatePool != null && this.updatePool.equals(service))) {
			this.updatePool.shutdown();
			this.updatePool = null;
		}
    }    
    protected boolean isUpdating() {
		return updating;
	}
	protected void setUpdating(boolean value) {
		if (this.updating != value) {
			this.updating = value;
			if (value) {
				this.getUpdatePool().scheduleWithFixedDelay(new Runnable() {
					@Override
					public void run() {
						MainService service = Services.main();
						
						try {
							UpdatesDTO dto = service.getUpdates();
							if (dto != null) {
								MainActivity.this.asyncRegisterUpdates(dto);	
							}
						} catch (Exception e) {
							MainActivity.this.asyncError(e);
						}
					}
				}, 10, 10, TimeUnit.SECONDS);
			} else {
				this.setUpdatePool(null);
			}
		}
	}

	public static MainActivity getInstance() {
		return instance;
	}

	public EventsAdapter getEventsAdapter() {
		if (this.eventsAdapter == null) {
			this.eventsAdapter = new EventsAdapter(this);
		}
		return eventsAdapter;
	}

	protected ImageButton getImgbInformarDeslocamento() {
    	if (this.imgbInformarDeslocamento == null) {
    		this.imgbInformarDeslocamento = (ImageButton)this.findViewById(R.id.activity_main_imgbInformarDeslocamento);
    	}
		return imgbInformarDeslocamento;
	}

	protected ImageButton getImgbRequisitarCarona() {
		if (this.imgbRequisitarCarona == null) {
			this.imgbRequisitarCarona = (ImageButton)this.findViewById(R.id.activity_main_imgbRequisitarCarona);
		}
		return imgbRequisitarCarona;
		
	}

	protected ImageButton getImgbMudarPerfil() {
		if (this.imgbMudarPerfil == null) {
			this.imgbMudarPerfil = (ImageButton)this.findViewById(R.id.activity_main_imgbMudarPerfil);
		}
		return imgbMudarPerfil;
	}
	
	protected ListView getLstvEvents() {
		if (this.lstvEvents == null) {
			this.lstvEvents = (ListView)this.findViewById(R.id.activity_main_lstvEvents);
		}
		return this.lstvEvents;
	}
	
	protected TextView getTxvPerfil() {
		if (this.txvPerfil == null) {
			this.txvPerfil = (TextView)this.findViewById(R.id.activity_main_txvPerfil);
		}
		return this.txvPerfil;
	}
	
	private void refresh() {
		MainService service = Services.main();	
		try {
			this.setModel(service.get());
		} catch (Exception e) {
			App.error(e);
		}
	}
	@Override
	public void onClick(View v) {
		if (this.getImgbMudarPerfil() == v) {
			this.alternar();
		} else if (this.getImgbRequisitarCarona() == v) {
			this.requisitarTrecho();
		} else if (this.getImgbInformarDeslocamento() == v) {
			this.informarDeslocamento();
		} else if (v.getTag() != null && v.getTag() instanceof DeslocamentoRow) {
			DeslocamentoRow row = (DeslocamentoRow)v.getTag();
			this.visualizarDeslocamento(row.getModel());
		}
	}	
	private void visualizarDeslocamento(DeslocamentoDTO deslocamento) {
		this.startModelActivity(this, deslocamento, VisualizarDeslocamentoActivity.class);
	}
	
	private void informarDeslocamento() {
		Intent intent = new Intent(this, InformarDeslocamentoActivity.class);
		this.startActivityForResult(intent, REQUEST_CODE_INFORMAR_DESLOCAMENTO);
	}
	private void requisitarTrecho() {
		Intent intent = new Intent(this, SolicitarDeslocamentoActivity.class); 
		this.startActivityForResult(intent, REQUEST_CODE_REQUISITAR_TRECHO);
	}
	private void alternar() {
		MainService service = Services.main();
		try {
			this.setModel(service.alternarPerfil());
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void confirmarTrecho(TrechoDTO trecho) {
		TrechoService service = Services.trecho();
		try {
			service.confirmar(trecho);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void negarTrecho(TrechoDTO trecho) {
		TrechoService service = Services.trecho();
		try {
			service.negar(trecho);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void cancelarTrecho(TrechoDTO trecho) {
		TrechoService service = Services.trecho();
		try {
			service.cancelar(trecho);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void embarcarTrecho(TrechoDTO trecho) {
		TrechoService trecService = Services.trecho();
		try {
			trecService.embarque(LocalizacaoDTO.fromLocation(LocationTracker.getInstance().getLastKnown()), trecho);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void desembarcarTrecho(TrechoDTO trecho) {
		TrechoService trecService = Services.trecho();
		try {
			trecService.desembarque(LocalizacaoDTO.fromLocation(LocationTracker.getInstance().getLastKnown()), trecho);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void cancelarDeslocamento(DeslocamentoDTO deslocamento) {
		DeslocamentoService service = Services.deslocamento();
		try {
			service.cancelar(deslocamento);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	private void finalizarDeslocamento(DeslocamentoDTO deslocamento) {
		DeslocamentoService service = Services.deslocamento();
		try {
			service.finalizar(deslocamento);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	
	private void rastrearMotorista(TrechoDTO trecho) {
		Intent intent = new Intent(this, VisualizarLocalizacaoActivity.class);
		intent.putExtra(UsuarioDTO.class.getName(), trecho.getDeslocamento().getMotorista());
		this.startActivity(intent);
	}
	
	private void registrarAvaliacao(AvaliacaoDTO avaliacao) {
		AvaliacaoService service = Services.avaliacao();
		try {
			service.registrar(avaliacao);
			this.refresh();
		} catch (Exception e) {
			App.error(e);
		}
	}
	
	private void editarAvaliacao(final AvaliacaoRow row) {
		RatingDialog dialog = new RatingDialog(this);
		AvaliacaoDTO model = row.getModel();
		dialog.setDescricao(model.getDescricao());
		dialog.setRating((((float)model.getQualificacao()) + 3) / 2);
		dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
			
			@Override
			public void onDismiss(DialogInterface dialog) {
				RatingDialog ratingDialog = (RatingDialog)dialog;
				row.setValues(ratingDialog.getDescricao(), ratingDialog.getRating());
			}
		});
		dialog.show();
	}
	
	private void registerUpdates(UpdatesDTO updates) {
		if (updates != null) {
			for (TrechoDTO item : updates.getPutAceite()) {
				this.getEventsAdapter().getAceiteAdapter().put(item);
			}
			for (AvaliacaoDTO item : updates.getPutAvaliacao()) {
				this.getEventsAdapter().getAvaliacaoAdapter().put(item);
			}
			for (MensagemDTO item : updates.getPutMensagem()) {
				this.getEventsAdapter().getMensagemAdapter().put(item);
			}
			for (TrechoDTO item : updates.getPutTrecho()) {
				this.getEventsAdapter().getTrechoAdapter().put(item);
			}
			for (TrechoDTO item : updates.getRemoveAceite()) {
				this.getEventsAdapter().getAceiteAdapter().remove(item);
			}
			for (TrechoDTO item : updates.getRemoveTrecho()) {
				this.getEventsAdapter().getTrechoAdapter().remove(item);
			}
		}
	}
	
	private void asyncRegisterUpdates(final UpdatesDTO updates) {
		this.runOnUiThread(new Runnable() {
			@Override
			public void run() {
				MainActivity.this.registerUpdates(updates);
			}
		});
	}
	private void asyncError(final Exception e) {
		this.runOnUiThread(new Runnable() {
			@Override
			public void run() {
				App.error(e);
			}
		});
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		
		switch (requestCode) {
		case REQUEST_CODE_INFORMAR_DESLOCAMENTO:
		case REQUEST_CODE_REQUISITAR_TRECHO:
			if (resultCode == Activity.RESULT_OK) {
				this.refresh();
			}
			break;
		default:
			break;
		}
	}

	@Override
	protected void onAuthCompleted() {
		super.onAuthCompleted();

		if (Services.isLoggedOn()) {
			this.refresh();
			this.setUpdating(true);
			LocationTracker.getInstance().setTracking(true);
		} else {
			this.setModel(null);
			this.setUpdating(false);
			LocationTracker.getInstance().setTracking(false);
		}
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		this.getEventsAdapter().getAceiteAdapter().setConfirmarActionListener(new RowActionListener<AceiteRow>() {
			@Override
			public void actionPerformed(AceiteRow row) {
				MainActivity.this.confirmarTrecho(row.getModel());
			}
		});
		this.getEventsAdapter().getAceiteAdapter().setNegarActionListener(new RowActionListener<AceiteRow>() {
			@Override
			public void actionPerformed(AceiteRow row) {
				MainActivity.this.negarTrecho(row.getModel());
			}
		});
		this.getEventsAdapter().getTrechoAdapter().setCancelarActionListener(new RowActionListener<TrechoRow>() {
			@Override
			public void actionPerformed(TrechoRow row) {
				MainActivity.this.cancelarTrecho(row.getModel());
			}
		});
		this.getEventsAdapter().getTrechoAdapter().setDesembarcarActionListener(new RowActionListener<TrechoRow>() {
			@Override
			public void actionPerformed(TrechoRow row) {
				MainActivity.this.desembarcarTrecho(row.getModel());
			}
		});
		this.getEventsAdapter().getTrechoAdapter().setEmbarcarActionListener(new RowActionListener<TrechoRow>() {
			@Override
			public void actionPerformed(TrechoRow row) {
				MainActivity.this.embarcarTrecho(row.getModel());
			}
		});
		this.getEventsAdapter().getTrechoAdapter().setLocalizacaoActionListener(new RowActionListener<TrechoRow>() {
			
			@Override
			public void actionPerformed(TrechoRow row) {
				MainActivity.this.rastrearMotorista(row.getModel());
			}
		});
		this.getEventsAdapter().getDeslocamentoAdapter().setCancelarActionListener(new RowActionListener<DeslocamentoRow>() {
			
			@Override
			public void actionPerformed(DeslocamentoRow row) {
				MainActivity.this.cancelarDeslocamento(row.getModel());
			}
		});
		this.getEventsAdapter().getDeslocamentoAdapter().setFinalizarActionListener(new RowActionListener<DeslocamentoRow>() {
			@Override
			public void actionPerformed(DeslocamentoRow row) {
				MainActivity.this.finalizarDeslocamento(row.getModel());
			}
		});
		this.getEventsAdapter().getAvaliacaoAdapter().setConfirmarActionListener(new RowActionListener<AvaliacaoRow>() {
			@Override
			public void actionPerformed(AvaliacaoRow row) {
				MainActivity.this.registrarAvaliacao(row.getModel());
			}
		});
		this.getEventsAdapter().getAvaliacaoAdapter().setEditarActionListener(new RowActionListener<AvaliacaoRow>() {
			@Override
			public void actionPerformed(AvaliacaoRow row) {
				MainActivity.this.editarAvaliacao(row);
			}
		});
        this.getLstvEvents().setAdapter(this.getNoDataEventsAdapter());
        
        this.getImgbMudarPerfil().setOnClickListener(this);
        this.getImgbRequisitarCarona().setOnClickListener(this);
        this.getImgbInformarDeslocamento().setOnClickListener(this);
        this.getEventsAdapter().getDeslocamentoAdapter().setOnClickListener(this);
	}
	
	
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(1, OPTIONS_MENU_ITEM_CONFIGURATION, 1, R.string.msgs_configuracao);
		return super.onCreateOptionsMenu(menu);
	}
	
	

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == OPTIONS_MENU_ITEM_CONFIGURATION) {
			Intent i = new Intent(this, ConfigurationActivity.class);
			this.startActivity(i);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void finish() {
		this.setUpdating(false);
		App.cleanUp();
		
		super.finish();
	}

	@Override
	protected void bindToView() {
		MainDTO main = this.getModel();
		this.getEventsAdapter().clear();
		
		if (main == null) {			
			this.getImgbInformarDeslocamento().setVisibility(View.GONE);
			this.getImgbMudarPerfil().setVisibility(View.GONE);
			this.getImgbRequisitarCarona().setVisibility(View.GONE);
			this.getTxvPerfil().setText(R.string.msgs_indisponivel);
		} else {
			this.getImgbInformarDeslocamento().setVisibility(main.isDeslocamentoInformavel() ? View.VISIBLE : View.GONE);
			this.getImgbMudarPerfil().setVisibility(main.isPerfilModificavel() ? View.VISIBLE : View.GONE);
			this.getImgbRequisitarCarona().setVisibility(main.isTrechoRequisitavel() ? View.VISIBLE : View.GONE);
			
			this.getTxvPerfil().setText(main.getPerfil());
			
			if (main.getAceite() != null) {
				for (TrechoDTO aceite : main.getAceite()) {
					this.getEventsAdapter().getAceiteAdapter().put(aceite);
				}	
			}
			if (main.getAvaliacao() != null) {
				for (AvaliacaoDTO avaliacao : main.getAvaliacao()) {
					this.getEventsAdapter().getAvaliacaoAdapter().put(avaliacao);
				}
			}
			if (main.getDeslocamento() != null) {
				for (DeslocamentoDTO deslocamento : main.getDeslocamento()) {
					this.getEventsAdapter().getDeslocamentoAdapter().put(deslocamento);
				}
			}
			if (main.getMensagem() != null) {
				for (MensagemDTO mensagem : main.getMensagem()) {
					this.getEventsAdapter().getMensagemAdapter().put(mensagem);
				}
			}
			if (main.getTrecho() != null) {
				for (TrechoDTO trecho : main.getTrecho()) {
					this.getEventsAdapter().getTrechoAdapter().put(trecho);
				}
			}
		}
	}
}